#include <seminix/syscall.h>
#include <seminix/uaccess.h>
#include <devices/serial.h>

#define __NEED_struct_iovec
#include <bits/alltypes.h>

static int do_write_output(struct iovec *kvec, unsigned long vlen)
{
    int i, ret = 0;
    unsigned long flags;

    for (i = 0; i < (int)vlen; i++) {
        void __user *buf = kvec[i].iov_base;
        ssize_t len = (ssize_t)kvec[i].iov_len;

        if (len < 0)
            return -EINVAL;

        if (unlikely(!access_ok(buf, len)))
            return -EFAULT;
    }

    console_device_lock(&flags);
    for (i = 0; i < (int)vlen; i++) {
        console_write_locked(kvec[i].iov_base, kvec[i].iov_len);
        ret += kvec[i].iov_len;
    }
    console_device_unlock(&flags);

    return ret;
}

// TODO
SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
        unsigned long, vlen)
{
    int ret;
    struct iovec *kvec;

    if (!vlen)
        return -EINVAL;

    kvec = kcalloc(vlen, sizeof (struct iovec), GFP_USER);
    if (!kvec)
        return -ENOMEM;

    if (copy_from_user(kvec, vec, vlen * sizeof (*vec))) {
        ret = -EFAULT;
        goto free;
    }

    switch (fd) {
    case 1:
        ret = do_write_output(kvec, vlen);
        break;
    default:
        panic("fd %pa vlen %pa\n", &fd, &vlen);
    }
free:
    kfree(kvec);
    return ret;
}
